import 'package:example/page/ext.dart';
import 'package:flujs/extension/console.dart';
import 'package:flujs/flujs.dart';
import 'package:flutter/material.dart';
import 'package:re_editor/re_editor.dart';
import 'package:re_highlight/languages/javascript.dart';
import 'package:re_highlight/styles/atom-one-light.dart';
import 'package:xterm/xterm.dart';
import 'package:flujs_qjs/qjs.dart' as qjs;
import 'package:flujs_jsc/jsc.dart' as jsc;

class PlaygroundController {
  final JSFRuntime qjsRt = qjs.getJSFRuntime();
  late final JSFContext qjsGctx = qjsRt.newContext()..loadExtension();
  final JSFRuntime jscRt = jsc.getJSFRuntime();
  late final JSFContext jscGctx = jscRt.newContext()..loadExtension();
  final terminal = Terminal();

  JSCall? qjsCall;
  JSCall? jscCall;

  void deactivate() {
    qjsGctx.free();
    qjsRt.free();
    jscGctx.free();
    jscRt.free();
  }
}

class PlaygroundPage extends StatefulWidget {
  PlaygroundPage(
      {super.key,
      required this.code,
      required this.title,
      required this.controller,
      this.replaceDefaultButton = false,
      this.customOpts});
  final String code;
  final String title;
  final bool replaceDefaultButton;

  PlaygroundController controller;

  final terminal = Terminal();

  List<Widget>? customOpts;

  @override
  State<PlaygroundPage> createState() => _PlaygroundPageState();
}

typedef JSCall = void Function(Terminal terminal, JSFContext ctx, String tag);

class _PlaygroundPageState extends State<PlaygroundPage> {
  late final codeController = CodeLineEditingController.fromText(widget.code);

  @override
  void initState() {
    super.initState();
    kFlujsLogger = TerminalLogger(terminal: widget.terminal);
  }

  @override
  void deactivate() {
    super.deactivate();
    widget.controller
      ..jscGctx.free()
      ..qjsGctx.free()
      ..jscRt.free()
      ..qjsRt.free();
  }

  @override
  Widget build(BuildContext context) {
    final opts = <Widget>[];
    if (widget.customOpts != null) {
      opts.addAll(widget.customOpts!);
    }
    if (!widget.replaceDefaultButton) {
      opts.addAll([
        ElevatedButton(
            onPressed: () {
              if (widget.controller.qjsCall != null) {
                widget.controller.qjsCall!
                    .call(widget.terminal, widget.controller.qjsGctx, 'qjs');
                return;
              }
              widget.terminal
                ..write(
                    '[Quickjs] ${widget.controller.qjsGctx.eval(widget.code, sourceURL: "Playground").toString()}')
                ..nextLine();
            },
            child: Text('Quickjs')),
        ElevatedButton(
            onPressed: () {
              if (widget.controller.jscCall != null) {
                widget.controller.jscCall!
                    .call(widget.terminal, widget.controller.jscGctx, 'jsc');
                return;
              }
              widget.terminal
                ..write(
                    '[JavaScriptCore] ${widget.controller.jscGctx.eval(widget.code, sourceURL: "Playground").toString()}')
                ..nextLine();
            },
            child: Text('JavaScriptCore')),
      ]);
    }

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox(
            height: 300,
            child: CodeEditor(
              controller: codeController,
              style: CodeEditorStyle(
                  codeTheme: CodeHighlightTheme(languages: {
                'javascript': CodeHighlightThemeMode(mode: langJavascript)
              }, theme: atomOneLightTheme)),
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Row(
              spacing: 8,
              mainAxisAlignment: MainAxisAlignment.end,
              children: opts.toList(),
            ),
          ),
          Expanded(
              child: TerminalView(
            widget.terminal,
          ))
        ],
      ),
    );
  }
}
